/**
 * 测试币安状态监控服务
 * Mock API数据并测试各个方法
 */

require('dotenv').config();
const path = require('path');

// 设置工作目录到项目根目录
const projectRoot = __dirname;
process.chdir(projectRoot);

const BinanceStatusService = require(path.join(projectRoot, 'src/services/binanceStatusService'));
const logger = require(path.join(projectRoot, 'src/utils/logger'));

// Mock axios
const originalAxios = require('axios');

class MockAxios {
  constructor() {
    this.mockResponses = new Map();
    this.callHistory = [];
  }

  // 设置mock响应
  setMockResponse(url, response) {
    this.mockResponses.set(url, response);
  }

  // 模拟axios.get方法
  async get(url, config = {}) {
    this.callHistory.push({ url, config, timestamp: new Date() });
    
    // 模拟网络延迟
    await new Promise(resolve => setTimeout(resolve, 100));
    
    // 检查是否有对应的mock响应
    for (const [mockUrl, mockResponse] of this.mockResponses.entries()) {
      if (url.includes(mockUrl) || mockUrl.includes('ping')) {
        if (mockResponse.shouldThrow) {
          throw new Error(mockResponse.error || 'Mock error');
        }
        return mockResponse;
      }
    }
    
    // 默认返回ping响应
    if (url.includes('/ping')) {
      return { status: 200, data: {} };
    }
    
    throw new Error(`No mock response configured for: ${url}`);
  }

  // 获取调用历史
  getCallHistory() {
    return this.callHistory;
  }

  // 清除调用历史
  clearCallHistory() {
    this.callHistory = [];
  }
}

// 创建mock实例
const mockAxios = new MockAxios();

// 替换axios
require.cache[require.resolve('axios')].exports = mockAxios;

async function testBinanceStatusService() {
  logger.info('🧪 开始测试币安状态监控服务...');
  
  try {
    // 创建服务实例
    const statusService = new BinanceStatusService();
    
    // 准备Mock数据
    setupMockData(mockAxios);
    
    // 测试1: 检查连接
    logger.info('📡 测试1: 检查API连接...');
    const connectionOk = await statusService.checkConnection();
    logger.info(`   连接状态: ${connectionOk ? '✅ 正常' : '❌ 失败'}`);
    
    // 测试2: 获取现货交易对状态
    logger.info('📊 测试2: 获取现货交易对状态...');
    const spotSymbols = await statusService.fetchSpotExchangeInfo();
    logger.info(`   获取到 ${spotSymbols.length} 个现货交易对状态`);
    if (spotSymbols.length > 0) {
      logger.info(`   示例: ${spotSymbols.slice(0, 3).map(s => `${s.symbol}(${s.status})`).join(', ')}`);
    }
    
    // 测试3: 获取期货交易对状态
    logger.info('📊 测试3: 获取期货交易对状态...');
    const futuresSymbols = await statusService.fetchFuturesExchangeInfo();
    logger.info(`   获取到 ${futuresSymbols.length} 个期货交易对状态`);
    if (futuresSymbols.length > 0) {
      logger.info(`   示例: ${futuresSymbols.slice(0, 3).map(s => `${s.symbol}(${s.status})`).join(', ')}`);
    }
    
    // 测试4: 获取所有交易对状态
    logger.info('📈 测试4: 获取所有交易对状态...');
    const allSymbols = await statusService.fetchAllSymbolStatus();
    logger.info(`   总计获取到 ${allSymbols.length} 个交易对状态`);
    
    // 测试5: 状态变化检测（第一次检查）
    logger.info('🔍 测试5: 第一次状态检查（建立基线）...');
    let alerts = statusService.checkStatusChanges(allSymbols);
    logger.info(`   第一次检查，建立基线: ${allSymbols.length} 个交易对，${alerts.length} 个变化`);
    
    // 测试6: 模拟状态变化
    logger.info('⚡ 测试6: 模拟状态变化...');
    const modifiedSymbols = simulateStatusChanges(allSymbols);
    alerts = statusService.checkStatusChanges(modifiedSymbols);
    logger.info(`   检测到 ${alerts.length} 个状态变化`);
    
    alerts.forEach(alert => {
      logger.info(`   ${alert.changeType === 'CRITICAL' ? '🚨' : 'ℹ️ '} ${alert.message}`);
    });
    
    // 测试7: 完整状态检查
    logger.info('🎯 测试7: 执行完整状态检查...');
    const checkResult = await statusService.performStatusCheck();
    logger.info(`   检查结果: ${checkResult.success ? '✅ 成功' : '❌ 失败'}`);
    logger.info(`   消息: ${checkResult.message}`);
    logger.info(`   耗时: ${checkResult.duration}ms`);
    
    if (checkResult.statusStats) {
      const stats = checkResult.statusStats;
      logger.info(`   统计: 总计 ${stats.total} 个交易对`);
      logger.info(`     - TRADING: ${stats.summary.trading}`);
      logger.info(`     - BREAK: ${stats.summary.break}`);
      logger.info(`     - 其他: ${stats.summary.others}`);
      logger.info(`     - 现货: ${stats.summary.spot}`);
      logger.info(`     - 期货: ${stats.summary.futures}`);
    }
    
    // 测试8: 生成状态统计
    logger.info('📊 测试8: 生成状态统计...');
    const stats = statusService.generateStatusStats(allSymbols);
    logger.info(`   统计信息生成完成:`);
    logger.info(`     按状态: ${JSON.stringify(stats.byStatus)}`);
    logger.info(`     按类型: ${JSON.stringify(stats.byType)}`);
    
    // 测试9: 获取服务状态
    logger.info('🔧 测试9: 获取服务状态...');
    const serviceStatus = statusService.getServiceStatus();
    logger.info(`   服务名称: ${serviceStatus.name}`);
    logger.info(`   描述: ${serviceStatus.description}`);
    logger.info(`   监控的交易对数: ${serviceStatus.monitoredSymbols}`);
    logger.info(`   监控端点: ${serviceStatus.endpoints.length} 个`);
    
    // 测试10: 清空状态历史
    logger.info('🧹 测试10: 清空状态历史...');
    statusService.clearStatusHistory();
    const statusAfterClear = statusService.getServiceStatus();
    logger.info(`   清空后监控的交易对数: ${statusAfterClear.monitoredSymbols}`);
    
    // 测试11: 错误处理测试
    logger.info('⚠️ 测试11: 错误处理测试...');
    await testErrorHandling(mockAxios, statusService);
    
    // 显示API调用历史
    logger.info('📋 API调用历史:');
    const callHistory = mockAxios.getCallHistory();
    callHistory.forEach((call, index) => {
      const shortUrl = call.url.replace(/https:\/\/[^\/]+/, '');
      logger.info(`   ${index + 1}. ${shortUrl} (${call.timestamp.toLocaleTimeString()})`);
    });
    
    logger.success('🎉 币安状态监控服务测试完成！');
    
  } catch (error) {
    logger.error(`测试过程中出错: ${error.message}`);
    logger.error(error.stack);
  }
}

/**
 * 设置Mock数据
 */
function setupMockData(mockAxios) {
  // Mock 现货API响应
  const spotResponse = {
    status: 200,
    data: {
      symbols: [
        { symbol: 'BTCUSDT', status: 'TRADING' },
        { symbol: 'ETHUSDT', status: 'TRADING' },
        { symbol: 'ADAUSDT', status: 'TRADING' },
        { symbol: 'DOGEUSDT', status: 'BREAK' },
        { symbol: 'DOTUSDT', status: 'TRADING' },
        { symbol: 'LINKUSDT', status: 'TRADING' },
        // 添加一些非USDT交易对（应该被过滤掉）
        { symbol: 'BTCETH', status: 'TRADING' },
        { symbol: 'ETHBNB', status: 'TRADING' }
      ]
    }
  };

  // Mock 期货API响应
  const futuresResponse = {
    status: 200,
    data: {
      symbols: [
        { symbol: 'BTCUSDT', status: 'TRADING' },
        { symbol: 'ETHUSDT', status: 'TRADING' },
        { symbol: 'ADAUSDT', status: 'BREAK' },
        { symbol: 'BNBUSDT', status: 'TRADING' },
        { symbol: 'SOLUSDT', status: 'TRADING' },
        // 添加一些非USDT交易对（应该被过滤掉）
        { symbol: 'BTCBUSD', status: 'TRADING' }
      ]
    }
  };

  mockAxios.setMockResponse('/api/v3/exchangeInfo', spotResponse);
  mockAxios.setMockResponse('/fapi/v1/exchangeInfo', futuresResponse);
  mockAxios.setMockResponse('/ping', { status: 200, data: {} });
}

/**
 * 模拟状态变化
 */
function simulateStatusChanges(originalSymbols) {
  const modifiedSymbols = [...originalSymbols];
  
  // 模拟一些状态变化
  if (modifiedSymbols.length > 0) {
    // 让第一个TRADING变成BREAK（关键告警）
    const tradingSymbol = modifiedSymbols.find(s => s.status === 'TRADING');
    if (tradingSymbol) {
      tradingSymbol.status = 'BREAK';
      logger.info(`   🔄 模拟: ${tradingSymbol.type} ${tradingSymbol.symbol} TRADING → BREAK`);
    }
    
    // 让一个BREAK变成TRADING（恢复）
    const breakSymbol = modifiedSymbols.find(s => s.status === 'BREAK');
    if (breakSymbol) {
      breakSymbol.status = 'TRADING';
      logger.info(`   🔄 模拟: ${breakSymbol.type} ${breakSymbol.symbol} BREAK → TRADING`);
    }
  }
  
  return modifiedSymbols;
}

/**
 * 测试错误处理
 */
async function testErrorHandling(mockAxios, statusService) {
  // 临时设置错误响应
  mockAxios.setMockResponse('/api/v3/exchangeInfo', {
    shouldThrow: true,
    error: '网络连接超时'
  });
  
  try {
    const result = await statusService.fetchSpotExchangeInfo();
    logger.info(`   错误处理测试: 返回 ${result.length} 个结果（应该为0）`);
  } catch (error) {
    logger.info(`   错误处理测试: 捕获到错误 - ${error.message}`);
  }
  
  // 恢复正常响应
  setupMockData(mockAxios);
}

// 运行测试
testBinanceStatusService().then(() => {
  logger.info('👋 测试脚本执行完成');
  process.exit(0);
}).catch(error => {
  logger.error(`测试失败: ${error.message}`);
  process.exit(1);
});
